package zhuzx.report;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.zhuzx.util.GeneralUtil;
import org.zhuzx.util.JdbcUtil;
import org.zhuzx.util.ListTextDataUtil;
import org.zhuzx.util.MicroUtil;

public class JavaScriptResolver {
	
	private static final Map<String, Map<String,String>> dataDictionary = new HashMap<>();
	private static Map<String,String> urlMappingName;
	static {
		Map<String,String> keyAndSql = GeneralUtil.loadPropsFileFromClassDirectory(JavaScriptResolver.class, "sqlForDataDict");
		Connection conn = JdbcUtil.getDbConn(null);
		urlMappingName = ListTextDataUtil.createDataDictionaryByTwoField(JdbcUtil.executeQuery(
				"SELECT url, name FROM permission WHERE TYPE = 'F' AND url IS NOT NULL AND url != ''", conn));
		for (Map.Entry<String, String> pair : keyAndSql.entrySet()) {
			List<Map<String,String>> list = JdbcUtil.executeQuery(pair.getValue(), conn);
			Map<String,String> result = ListTextDataUtil.createDataDictionaryByTwoField(list);
			dataDictionary.put(pair.getKey(), result);
			dataDictionary.put(MicroUtil.convertUnderlineToCamelCased(pair.getKey()), result);
		}
		try {
			conn.close();
		} catch (SQLException e1) {}
	}
	
	public static String getNameByUrl(String url) {
		String fileName = urlMappingName.get(url);
		if (fileName == null) {
			fileName = url.substring(url.lastIndexOf('/')+1);
			int i = fileName.indexOf('.');
			if (i > -1) {
				fileName = fileName.substring(0, i);
			}
		}
		return fileName;
	}
	
	public static List<Map<String,String>> convertResultSet(List<Map<String,String>> list, String pageCode, String columnsCode) {
		columnsCode = GeneralUtil.getNotBlankString(getColumnsCode(pageCode), columnsCode);
		String[] fields = MicroUtil.extractMatches(columnsCode, "\\{\\s*field\\s*:\\s*'.*?'");
		String[] titles = MicroUtil.extractMatches(columnsCode, ",\\s*title\\s*:\\s*'.*?'");
		for (int i = 0; i < fields.length; i++) {
			String field = fields[i];
			field = field.substring(field.indexOf('\'')+1, field.lastIndexOf('\''));
			fields[i] = field;
			String title = titles[i];
			title = title.substring(title.indexOf('\'')+1, title.lastIndexOf('\''));
			titles[i] = title;
		}
		String[] columns = columnsCode.substring(1, columnsCode.length()-1).split("\\}\\s*,\\s*\\{");
		String[] formatters = getFormatters(columns, pageCode);
		modifyValueByDataDictionary(list, fields, formatters);
		modifyValueByBranchStatement(list, fields, formatters);
		
		fields = getDisplayFields(fields, columns);
		List<Map<String, String>> newList = new ArrayList<Map<String, String>>(list.size());
		for (Map<String, String> row : list) {
			Map<String,String> newRow = new LinkedHashMap<>();
			for (int i = 0; i < fields.length; i++) {
				if (fields[i] == null) continue;
				if (!GeneralUtil.isBlank(titles[i])) {
					newRow.put(titles[i], row.get(fields[i]));
				}
			}
			newList.add(newRow);
		}
		return newList;
	}

	private static String getColumnsCode(String pageCode) {
		int start = MicroUtil.findFirst(pageCode, ",\\s*columns\\s*:\\s*\\[\\s*\\[");
		int end = MicroUtil.findFirst(pageCode, "\\}\\s*,?\\s*\\]\\s*\\]");
		if (end == -1) return null;
		String columnsCode = pageCode.substring(start, end+1);
		columnsCode = columnsCode.substring(columnsCode.indexOf('{'));
		return columnsCode;
	}
	
	private static String[] getFormatters(String[] columns, String pageCode) {
		String[] formatters = new String[columns.length];
		for (int i = 0; i < columns.length; i++) {
			int index = columns[i].indexOf("formatter");
			if (index > -1) {
				String formatter = columns[i].substring(columns[i].indexOf(':', index+"formatter".length()) + 1);
				int fmtCodeIndex = formatter.indexOf('{');
				if (fmtCodeIndex == -1) {//函数定义在外部
					String regex = "var\\s+" + formatter.trim() + "\\s*=\\s*function\\s*\\(";
					regex = "(" + regex + ")|(function\\s+" + formatter.trim() + "\\s*\\()";
					int[] fmtSign = MicroUtil.findMatches(pageCode, regex);
					if (fmtSign.length == 1) {
						formatters[i] = MicroUtil.substringByMates(pageCode.substring(fmtSign[0]), '{', '}').trim();
					} else {
						System.out.println(">>>>未找到匹配的外部函数定义：" + formatter);
					}
				} else {
					formatters[i] = MicroUtil.substringByMates(formatter, '{', '}').trim();
				}
			}
		}
		return formatters;
	}
	
	private static void modifyValueByDataDictionary(List<Map<String,String>> list, String[] fields, String[] formatters) {
		String regex = "return\\s+\\w+\\[.+?\\];?";
		for (int i = 0; i < fields.length; i++) {
			String fmtCode = formatters[i];
			if (fmtCode == null) continue;
			if (fmtCode.matches(regex)) {//return companyMap["id_" + value];
				Map<String,String> dataMap = dataDictionary.get(fields[i]);
				if (dataMap == null) {
					String mapName = fmtCode.substring(fmtCode.indexOf("return")+"return ".length(), fmtCode.indexOf('[')).trim();
					System.out.println(">>>>缺失数据字典：" + mapName);
				} else {
					for (Map<String, String> map : list) {
						map.put(fields[i], dataMap.get(map.get(fields[i])));
					}
				}
			}
		}
	}
	
	private static void modifyValueByBranchStatement(List<Map<String,String>> list, String[] fields, String[] formatters) {
		String regex = "if\\s*\\(.+?==.+?\\)\\s*\\{?\\s*return .*?;";
		for (int i = 0; i < fields.length; i++) {
			String fmtCode = formatters[i];
			if (fmtCode == null) continue;
			String[] branches = MicroUtil.extractMatches(fmtCode, regex);
			for (Map<String, String> map : list) {
				String value = map.get(fields[i]);
				if (value == null) continue;
				if (branches.length > 0) {
					for (String bran : branches) {
						String expression = MicroUtil.substringByMates(bran, '(', ')');
						String[] conds = expression.split("\\&\\&|\\|\\|");
						for (String cond : conds) {
							String[] pair = cond.trim().split("\\s*==\\s*");
							if (value.equals(husking(pair[1]))) {
								int dispStart = bran.indexOf("return ") + "return ".length();
								String displayed = bran.substring(dispStart, bran.length()-1).trim();
								displayed = husking(displayed);
								map.put(fields[i], displayed);
							}
						}
					}
				}
			}
		}
	}
	
	private static String husking(String original) {
		char[] hulls = {'"', '\''};
		for (char c : hulls) {
			if (original.charAt(0) == c && original.charAt(original.length()-1) == c) {
				return original.substring(1, original.length()-1);
			}
		}
		return original;
	}
	
	private static String[] getDisplayFields(String[] fields, String[] columns) {
		String[] displayFields = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			String colu = columns[i];
			if (!colu.matches(".*hidden\\s*:\\s*true.*")) {
				displayFields[i] = fields[i];
			}
		}
		return displayFields;
	}
	
}